package com.yht.weblog.web.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.yht.weblog.admin.event.ReadArticleEvent;
import com.yht.weblog.common.domain.dos.*;
import com.yht.weblog.common.domain.mapper.*;
import com.yht.weblog.common.enums.ResponseCodeEnum;
import com.yht.weblog.common.exception.BizException;
import com.yht.weblog.common.utils.PageResponse;
import com.yht.weblog.common.utils.Response;
import com.yht.weblog.web.convert.ArticleConvert;
import com.yht.weblog.web.markdown.MarkdownHelper;
import com.yht.weblog.web.model.vo.article.*;
import com.yht.weblog.web.model.vo.category.FindCategoryListRspVO;
import com.yht.weblog.web.model.vo.tag.FindTagListRspVO;
import com.yht.weblog.web.service.ArticleService;
import com.yht.weblog.web.utils.MarkdownStatsUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author: yht
 * @date: 2024/1/9 23:03
 * @description:
 **/
@Service
@Slf4j
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private ArticleMapper articleMapper;
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private TagMapper tagMapper;
    @Autowired
    private ArticleCategoryRelMapper articleCategoryRelMapper;
    @Autowired
    private ArticleTagRelMapper articleTagRelMapper;
    @Autowired
    private ArticleContentMapper articleContentMapper;
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    /**
     * 根据条件查找文章页面列表
     *
     * @param findIndexArticlePageListReqVO 请求参数对象
     * @return 响应结果对象
     */
    @Override
    public Response findArticlePageList(FindIndexArticlePageListReqVO findIndexArticlePageListReqVO) {

        Long current = findIndexArticlePageListReqVO.getCurrent();
        Long size = findIndexArticlePageListReqVO.getSize();

        // 根据条件查询文章DO页面列表
        Page<ArticleDO> articleDOPage = articleMapper.selectPageList(current, size, null, null, null);
        List<ArticleDO> articleDOS = articleDOPage.getRecords();

        List<FindIndexArticlePageListRspVO> vos = null;

        if (!CollectionUtils.isEmpty(articleDOS)) {
            // 将文章DO转换为文章页列表VO
            vos = articleDOS.stream().map(articleDO -> ArticleConvert.INSTANCE.convertDO2VO(articleDO))
                    .collect(Collectors.toList());

            // 获取文章ID列表
            List<Long> articleIds = articleDOS.stream().map(ArticleDO::getId).collect(Collectors.toList());

            // 查询分类DO列表
            List<CategoryDO> categoryDOS = categoryMapper.selectList(Wrappers.emptyWrapper());

            // 构建分类ID名称映射表
            Map<Long, String> categoryIdNameMap = categoryDOS.stream().collect(Collectors.toMap(CategoryDO::getId, CategoryDO::getName));

            // 查询文章分类关系DO列表
            List<ArticleCategoryRelDO> articleCategoryRelDOS = articleCategoryRelMapper.selectByArticleIds(articleIds);

            // 遍历VO列表，将分类信息添加到VO中
            vos.forEach(vo -> {
                Long currArticleId = vo.getId();

                Optional<ArticleCategoryRelDO> optional = articleCategoryRelDOS.stream().filter(rel -> Objects.equals(rel.getArticleId(), currArticleId)).findAny();


                if (optional.isPresent()) {

                    ArticleCategoryRelDO articleCategoryRelDO = optional.get();
                    Long categoryId = articleCategoryRelDO.getCategoryId();

                    String categoryName = categoryIdNameMap.get(categoryId);

                    // 构建分类列表响应对象
                    FindCategoryListRspVO findCategoryListRspVO = FindCategoryListRspVO.builder()
                            .id(categoryId)
                            .name(categoryName)
                            .build();

                    vo.setCategory(findCategoryListRspVO);
                }
            });


            // 查询标签DO列表
            List<TagDO> tagDOS = tagMapper.selectList(Wrappers.emptyWrapper());

            // 构建标签ID名称映射表
            Map<Long, String> mapIdNameMap = tagDOS.stream().collect(Collectors.toMap(TagDO::getId, TagDO::getName));

            // 查询文章标签关系DO列表
            List<ArticleTagRelDO> articleTagRelDOS = articleTagRelMapper.selectByArticleIds(articleIds);

            // 遍历VO列表，将标签信息添加到VO中
            vos.forEach(vo -> {
                Long currArticleId = vo.getId();

                List<ArticleTagRelDO> articleTagRelDOList = articleTagRelDOS.stream().filter(rel -> Objects.equals(rel.getArticleId(), currArticleId)).collect(Collectors.toList());

                List<FindTagListRspVO> findTagListRspVOS = Lists.newArrayList();

                articleTagRelDOList.forEach(articleTagRelDO -> {
                    Long tagId = articleTagRelDO.getTagId();

                    String tagName = mapIdNameMap.get(tagId);

                    // 构建标签列表响应对象
                    FindTagListRspVO findTagListRspVO = FindTagListRspVO.builder()
                            .id(tagId)
                            .name(tagName)
                            .build();

                    findTagListRspVOS.add(findTagListRspVO);
                });
                vo.setTags(findTagListRspVOS);
            });

        }
        return PageResponse.success(articleDOPage, vos);
    }

    /**
     * 根据条件查找文章页面列表
     *
     * @param findArticleDetailReqVO 请求参数对象
     * @return 响应结果对象
     */
    @Override
    public Response findArticleDetail(FindArticleDetailReqVO findArticleDetailReqVO) {

        // 获取文章ID
        Long articleId = findArticleDetailReqVO.getArticleId();

        // 根据文章ID查询文章DO
        ArticleDO articleDO = articleMapper.selectById(articleId);
        if (Objects.isNull(articleDO)) {
            log.warn("==> 该文章不存在， articleId: {}", articleId);
            throw new BizException(ResponseCodeEnum.ARTICLE_NOT_FOUND);
        }

        // 根据文章ID查询文章内容DO
        ArticleContentDO articleContentDO = articleContentMapper.selectByArticleId(articleId);

        // 查询正文内容
        String articleContent = articleContentDO.getContent();
        Integer articleWords = MarkdownStatsUtil.calculateWordCount(articleContent);
        String readTime = MarkdownStatsUtil.calculateReadingTime(articleWords);

        // 构建返回的响应数据对象
        FindArticleDetailRspVO vo = FindArticleDetailRspVO.builder()
                .title(articleDO.getTitle())
                .createTime(articleDO.getCreateTime())
                .content(MarkdownHelper.convertMarkdown2Html(articleContentDO.getContent()))
                .readNum(articleDO.getReadNum())
                .totalWords(articleWords)
                .readTime(readTime)
                .build();

        // 根据文章ID查询文章分类关系DO
        ArticleCategoryRelDO articleCategoryRelDO = articleCategoryRelMapper.selectByArticleId(articleId);

        // 根据分类ID查询分类DO
        CategoryDO categoryDO = categoryMapper.selectById(articleCategoryRelDO.getCategoryId());

        // 设置响应数据对象的分类ID和分类名称
        vo.setCategoryId(categoryDO.getId());
        vo.setCategoryName(categoryDO.getName());

        // 根据文章ID查询文章标签关系DO列表
        List<ArticleTagRelDO> articleTagRelDOS = articleTagRelMapper.selectByArticleId(articleId);

        // 获取文章标签ID列表
        List<Long> tagIds = articleTagRelDOS.stream().map(ArticleTagRelDO::getTagId).collect(Collectors.toList());

        // 根据标签ID列表查询标签DO列表
        List<TagDO> tagDOS = tagMapper.selectByIds(tagIds);

        // 构建标签列表VO列表
        List<FindTagListRspVO> tagVOS = tagDOS.stream()
                .map(tagDO -> FindTagListRspVO.builder()
                        .id(tagDO.getId())
                        .name(tagDO.getName())
                        .build())
                .collect(Collectors.toList());

        // 设置响应数据对象的标签列表
        vo.setTags(tagVOS);

        // 查询前一篇文章
        ArticleDO preArticleDO = articleMapper.selectPreArticle(articleId);

        if (Objects.nonNull(preArticleDO)) {
            // 构建前一篇文章VO
            FindPreNextArticleRspVO preArticleVO = FindPreNextArticleRspVO.builder()
                    .articleId(preArticleDO.getId())
                    .articleTitle(preArticleDO.getTitle())
                    .build();

            // 设置响应数据对象的前一篇文章
            vo.setPreArticle(preArticleVO);
        }

        // 查询后一篇文章
        ArticleDO nextArticle = articleMapper.selectNextArticle(articleId);

        if (Objects.nonNull(nextArticle)) {
            // 构建后一篇文章VO
            FindPreNextArticleRspVO nextArticleVO = FindPreNextArticleRspVO.builder()
                    .articleId(nextArticle.getId())
                    .articleTitle(nextArticle.getTitle())
                    .build();

            // 设置响应数据对象的后一篇文章
            vo.setNextArticle(nextArticleVO);
        }
        // 发布文章阅读事件
        eventPublisher.publishEvent(new ReadArticleEvent(this, articleId));

        // 返回响应结果
        return Response.success(vo);
    }

}
